#ifndef __ASM_RISCV_SBI_H__
#define __ASM_RISCV_SBI_H__

#include "type.h"

#define SBI_SET_TIMER 0
#define SBI_PUTCHAR 1
#define SBI_GETCHAR 2

#define SBI_CALL(which, arg0, arg1, arg2, arg3) ({      \
    register register_t a0 asm("a0") = (register_t)(arg0);      \
    register register_t a1 asm("a1") = (register_t)(arg1);      \
    register register_t a2 asm("a2") = (register_t)(arg2);      \
    register register_t a3 asm("a3") = (register_t)(arg3);      \
    register register_t a7 asm("a7") = (register_t)(which);     \
    asm volatile("ecall"        \
                : "+r" (a0)    \
                : "r" (a1), "r" (a2), "r" (a3), "r"(a7) \
                : "memory");        \
    a0;         \
})

#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0, 0)
#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0, 0)
#define SBI_CALL_2(which, arg0, arg1)   SBI_CALL(which, arg0, arg1, 0, 0)
#define SBI_CALL_3(which, arg0, arg1, arh2) \
        SBI_CALL(which, arg0, arg1, arg2, 0)
#define SBI_CALL_4(which, arg0, arg1, arg2, arg3)       \
        SBI_CALL(which, arg0, arg1, arg2, arg3)
static inline void sbi_putchar(int ch)
{
    SBI_CALL_1(SBI_PUTCHAR, ch);
}
static inline int sbi_getchar(void)
{
    return SBI_CALL_0(SBI_GETCHAR);
}
static inline void sbi_set_time(register_t time)
{
    SBI_CALL_1(SBI_SET_TIMER, time);
}
void sbi_set_extern_interrupt(address_t func_pointer);
static inline void sbi_set_mie(void)
{
    SBI_CALL_0(0x0A000005);
}
#endif